package com.aplink.generic.adapter;

import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.ArrayList;

import android.content.Context;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.TextView;

import com.aplink.generic.GenericFragment;
import com.aplink.generic.constant.type.ActionType;
import com.aplink.generic.constant.type.ColumnType;
import com.aplink.generic.constant.type.DialogStatus;
import com.aplink.generic.dialog.ApLinkAlertDialog.DialogConfirmCallback;
import com.aplink.generic.dictionary.GenericDictionary;
import com.aplink.generic.interfaces.OnNotifyDataSetChanged;
import com.aplink.generic.pojo.ColumnSetting;
import com.aplink.generic.pojo.GenericObject;
import com.aplink.generic.pojo.controlspec.menu.PopupMenuSpec;
import com.aplink.generic.util.DateTimeUtils;
import com.aplink.generic.util.Language;
import com.aplink.generic.util.LogUtil;
import com.aplink.generic.util.ResourcesHelper;
import com.aplink.generic.widgets.ApLinkPopupMenu;
import com.aplink.generic.widgets.util.SwipeItemDeletion;
import com.aplink.generic.widgets.util.SwipeItemDeletion.HandleSwipeItemDeletion;
import com.aplink.sg.R;

public class ConfigAdapter extends BaseAdapter implements Filterable,
		DialogConfirmCallback {

	static class ViewHolder {
		public ArrayList<View> views;

		public ViewHolder() {
			this.views = new ArrayList<View>();
		}
	}

	private ArrayList<ColumnSetting> mColumnSettingList = new ArrayList<ColumnSetting>();
	private final Context mContext;
	private OnNotifyDataSetChanged mDataSetChanged;
	private ArrayList<GenericObject> mDisplayObjects;
	private GenericFragment mGenericFragment;
	private final String mLayoutSrc;
	private int mLayoutsrcID;
	private SwipeItemDeletion mOnTouchListener;
	private ArrayList<GenericObject> mOriginalObjects;

	private ArrayList<String> mSearchFileds;

	private String mValueField;

	private int rowHeight;

	public ConfigAdapter() {
		this.mContext = null;
		this.mOriginalObjects = null;
		this.mColumnSettingList = null;
		this.mLayoutSrc = "";
		mNotTranslate = new GenericDictionary<Integer, ColumnSetting>();
	}

	/**
	 * How to use this class, mAdapter = new
	 * GenericConfigAdapter(getApplicationContext
	 * (),genericObjectList,columnSettingList,"redeem_item_config"); Please
	 * remember that each row in this list is plugged its tag with its own
	 * object Therefore in detail page we just extract the object and parse as
	 * you want
	 * 
	 * @param mContext
	 * @param objects
	 * @param columnSettings
	 * @param layoutsrc
	 */
	@SuppressWarnings("unchecked")
	public ConfigAdapter(final GenericFragment genericFragment,
			final ArrayList<GenericObject> objects,
			final ArrayList<ColumnSetting> columnSettings, final int layoutsrc) {
		this.mGenericFragment = genericFragment;
		this.mContext = this.mGenericFragment.getApplicationContext();
		this.mOriginalObjects = objects;
		this.mDisplayObjects = (ArrayList<GenericObject>) objects.clone();
		this.mColumnSettingList = columnSettings;
		this.mLayoutsrcID = layoutsrc;
		mLayoutSrc = null;
		mNotTranslate = new GenericDictionary<Integer, ColumnSetting>();
	}

	/**
	 * How to use this class, mAdapter = new
	 * GenericConfigAdapter(getApplicationContext
	 * (),genericObjectList,columnSettingList,"redeem_item_config"); Please
	 * remember that each row in this list is plugged its tag with its own
	 * object Therefore in detail page we just extract the object and parse as
	 * you want
	 * 
	 * @param mContext
	 * @param objects
	 * @param columnSettings
	 * @param layoutsrc
	 */
	@SuppressWarnings("unchecked")
	public ConfigAdapter(final GenericFragment genericFragment,
			final ArrayList<GenericObject> objects,
			final ArrayList<ColumnSetting> columnSettings,
			final String layoutsrc) {
		this.mGenericFragment = genericFragment;
		this.mContext = this.mGenericFragment.getApplicationContext();
		this.mOriginalObjects = objects;
		this.mDisplayObjects = (ArrayList<GenericObject>) objects.clone();
		this.mColumnSettingList = columnSettings;
		this.mLayoutSrc = layoutsrc;
		mNotTranslate = new GenericDictionary<Integer, ColumnSetting>();
	}

	/**
	 * How to use this class, mAdapter = new
	 * GenericConfigAdapter(getApplicationContext
	 * (),genericObjectList,columnSettingList,"redeem_item_config"); Please
	 * remember that each row in this list is plugged its tag with its own
	 * object Therefore in detail page we just extract the object and parse as
	 * you want
	 * 
	 * @param mContext
	 * @param objects
	 * @param columnSettings
	 * @param layoutsrc
	 */
	@SuppressWarnings("unchecked")
	public ConfigAdapter(final GenericFragment genericFragment,
			final ArrayList<GenericObject> objects,
			final ArrayList<ColumnSetting> columnSettings,
			final String layoutsrc, SwipeItemDeletion onTouchListener) {
		this.mGenericFragment = genericFragment;
		this.mContext = this.mGenericFragment.getApplicationContext();
		this.mOriginalObjects = objects;
		this.mDisplayObjects = (ArrayList<GenericObject>) objects.clone();
		this.mColumnSettingList = columnSettings;
		this.mLayoutSrc = layoutsrc;
		mOnTouchListener = onTouchListener;
		mOnTouchListener.setConfigAdapter(this);
		mNotTranslate = new GenericDictionary<Integer, ColumnSetting>();
	}

	private View createViewFromResource(final int position, View convertView,
			final ViewGroup parent, int resource, int height) {
		ViewHolder viewHolder;
		if (convertView == null) {
			viewHolder = new ViewHolder();
			final LayoutInflater vi = (LayoutInflater) this.mContext
					.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			convertView = vi.inflate(resource, parent, false);
			for (final ColumnSetting columnSetting : this.mColumnSettingList) {
				final String controlName = columnSetting.getLinkMappingName();
				if (!controlName.isEmpty()) {
					final int idControl = ResourcesHelper
							.getViewIdByName(controlName);
					if (idControl == ResourcesHelper.RESOURCE_NOT_FOUND) {
						continue;
					}
					View view = null;
					if (idControl == convertView.getId()) {
						view = convertView;
					} else {
						view = convertView.findViewById(idControl);
					}
					view.setTag(columnSetting);
					viewHolder.views.add(view);
					mNotTranslate.put(idControl, columnSetting);
				}
			}
			translate(convertView, false);
			convertView.setTag(viewHolder);
			if (mOnTouchListener != null) {
				convertView.setOnTouchListener(mOnTouchListener);
			}
		} else {
			viewHolder = (ViewHolder) convertView.getTag();
		}
		final GenericObject object = this.mDisplayObjects.get(position);
		if (object == null) {
			return null;
		}
		for (final View view : viewHolder.views) {
			final ColumnSetting columnSetting = (ColumnSetting) view.getTag();
			final ColumnType columnType = columnSetting.getColType();
			final String columnName = columnSetting.getColumnName();
			String columnValue = "";
			if (!TextUtils.isEmpty(object.getValue(columnName))) {
				columnValue = object.getValue(columnName).toString();
			} else if (columnSetting.isStaicResource()) {
				if (object.containsKey(ColumnSetting.STATIC_RESOURCE)
						&& (object.getValue(ColumnSetting.STATIC_RESOURCE) != null)) {
					columnValue = object
							.getValue(ColumnSetting.STATIC_RESOURCE).toString();
				} else {
					columnValue = "";
				}
			}
			if (columnSetting.hasValueList()) {
				columnValue = columnSetting.getValueList().get(columnValue);
				if (TextUtils.isEmpty(columnValue)) {
					columnValue = columnSetting.getValueList().get(
							columnSetting.getValueList().getDefaultValue());
				}
			}
			if (columnType.equals(ColumnType.ContextMenu)) {
				final PopupMenuSpec popupMenuSpec = columnSetting
						.getPopupMenuSpec();
				final ApLinkPopupMenu customPopupMenu = new ApLinkPopupMenu(
						this.mGenericFragment, popupMenuSpec, view, null);
				customPopupMenu.setGenericObject(object);
				customPopupMenu.initView();
			} else if (columnType.equals(ColumnType.Image)) {
				if (view instanceof ImageView) {
					int iconID = ResourcesHelper
							.getDrawableIdByName(columnValue);
					((ImageView) view).setImageResource(iconID);
				}
			} else {
				if (view instanceof TextView) {
					String content = "";
					if (columnType.equals(ColumnType.DateTime)) {
						try {
							Double double1 = Double.parseDouble(columnValue);
							final long miliseconds = double1.longValue();
							if (TextUtils.isEmpty(columnSetting.getFormat())) {
								content = DateTimeUtils.getDateTime(
										miliseconds, null);
							} else {
								content = DateTimeUtils.getDateTime(
										miliseconds, columnSetting.getFormat());
							}
						} catch (final NumberFormatException e) {
							LogUtil.error(e.getMessage(), "getView", getClass()
									.getSimpleName());
						} catch (final ParseException e) {
							LogUtil.error(e.getMessage(), "getView", getClass()
									.getSimpleName());
						}
					} else if (columnType.equals(ColumnType.Text)) {
						content = columnValue;
					} else if (columnType.equals(ColumnType.Money)) {
						final Double number = Double.valueOf(columnValue);
						final DecimalFormat dec = new DecimalFormat(
								columnSetting.getFormat());
						content = dec.format(number);
					}
					((TextView) view).setText(Language.getInstance().get(
							content));
				}
			}
		}
		if (height != 0) {
			convertView.setLayoutParams(new LayoutParams(
					android.view.ViewGroup.LayoutParams.MATCH_PARENT, height));
		}
		return convertView;
	}

	@Override
	public int getCount() {
		return this.mDisplayObjects.size();
	}

	public ArrayList<GenericObject> getDisplayObjects() {
		return this.mDisplayObjects;
	}

	@Override
	public View getDropDownView(int position, View convertView, ViewGroup parent) {
		if (mLayoutSrc != null) {
			mLayoutsrcID = ResourcesHelper.getLayoutIdByName(this.mLayoutSrc);
		}
		return createViewFromResource(position, convertView, parent,
				mLayoutsrcID, 0);
	}

	@Override
	public Filter getFilter() {
		return new AdapterFilter(mSearchFileds, ConfigAdapter.this);
	}

	@Override
	public Object getItem(final int position) {
		if (!TextUtils.isEmpty(mValueField)) {
			return mDisplayObjects.get(position).get(mValueField).getValue();
		}
		return mDisplayObjects.get(position);
	}

	@Override
	public long getItemId(final int position) {
		return getItem(position).hashCode();
	}

	public final ArrayList<GenericObject> getOriginalObjects() {
		return mOriginalObjects;
	}

	public ArrayList<String> getSearchFileds() {
		return mSearchFileds;
	}

	public String getValueField() {
		return mValueField;
	}

	@Override
	public View getView(final int position, final View convertView,
			final ViewGroup parent) {
		if (mLayoutSrc != null) {
			mLayoutsrcID = ResourcesHelper.getLayoutIdByName(this.mLayoutSrc);
		}
		return createViewFromResource(position, convertView, parent,
				mLayoutsrcID, rowHeight);
	}

	@Override
	public void notifyDataSetChanged() {
		super.notifyDataSetChanged();
		if (mDataSetChanged != null) {
			mDataSetChanged.dataSetChanged();
		}
	}

	public void remove(GenericObject genericObject) {
		mSelectedObject = genericObject;
		if (mGenericFragment.getAlertDialog().has(ActionType.DELETE,
				DialogStatus.CONFIRM)) {
			mGenericFragment.getAlertDialog().get(ActionType.DELETE)
					.setDialogConfirmCallback(this);
			mGenericFragment.getAlertDialog().show(ActionType.DELETE,
					DialogStatus.CONFIRM);
		} else {
			onConfirmed();
		}
	}

	public void setDataSetChanged(OnNotifyDataSetChanged dataSetChanged) {
		mDataSetChanged = dataSetChanged;
	}

	public final void setDisplayObjects(
			final ArrayList<GenericObject> displayObjects) {
		mDisplayObjects.clear();
		mDisplayObjects.addAll(displayObjects);
		notifyDataSetChanged();
	}

	public void setOriginalObjects(ArrayList<GenericObject> originalObjects) {
		mOriginalObjects = originalObjects;
	}

	public void setRowHeight(int rowHeight) {
		this.rowHeight = rowHeight;
	}

	public void setSearchFileds(ArrayList<String> searchFileds) {
		mSearchFileds = searchFileds;
	}

	public void setValueField(String valueField) {
		mValueField = valueField;
	}

	private void translate(final View view, boolean isGetTag) {
		if (view instanceof ViewGroup) {
			for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
				translate(((ViewGroup) view).getChildAt(i), isGetTag);
			}
		} else {
			if (view instanceof TextView
					&& view.getClass().equals(TextView.class)
					&& !mNotTranslate.containsKey(view.getId())) {
				if (isGetTag) {
					if (view.getTag(R.id.TEXT_ENGLISH) instanceof String) {
						((TextView) view).setText(Language.getInstance().get(
								((TextView) view).getTag(R.id.TEXT_ENGLISH)
										.toString()));
					}
				} else {
					view.setTag(R.id.TEXT_ENGLISH, ((TextView) view).getText());
					((TextView) view).setText(Language.getInstance().get(
							((TextView) view).getText().toString()));
				}
			}
		}
	}

	private GenericDictionary<Integer, ColumnSetting> mNotTranslate;
	private GenericObject mSelectedObject;
	private HandleSwipeItemDeletion mHandleSwipeItemDeletion;

	@Override
	public void onConfirmed() {
		mDisplayObjects.remove(mSelectedObject);
		mOriginalObjects.remove(mSelectedObject);
		mGenericFragment.setSelectedObject(mSelectedObject);
		mGenericFragment.getEventHandler().sendAction(ActionType.DELETE);
		notifyDataSetChanged();
		mGenericFragment.getAlertDialog().get(ActionType.DELETE)
				.removeConfirmCallbackListener();
		mHandleSwipeItemDeletion.sendEmptyMessage(SwipeItemDeletion.REMOVE);
	}

	@Override
	public void onCanceled() {
		mHandleSwipeItemDeletion.sendEmptyMessage(SwipeItemDeletion.CANCEL);
	}

	public HandleSwipeItemDeletion getHandleSwipeItemDeletion() {
		return mHandleSwipeItemDeletion;
	}

	public void setHandleSwipeItemDeletion(
			HandleSwipeItemDeletion handleSwipeItemDeletion) {
		mHandleSwipeItemDeletion = handleSwipeItemDeletion;
	}
}
